import allure
import pytest
import requests
import json

mobile = "18814121299"
TOKEN = None

def set_token(value):
    global TOKEN
    TOKEN = value

def get_code():

    # 获取短信验证码
    url = f"https://dev.native.goldau.cn/server/custom/api/customUser/sendSmsCode/{mobile}/1"
    response = requests.get(url)
    print(f"获取短信验证码接口返回: {response.json()}")

    assert response.status_code == 200
    json_data = response.json()
    assert 'data' in json_data
    
    # 获取 'data' 字段的值
    data_value = json_data['data']
    print(f"完成获取短信验证码: {data_value}")

    return data_value
  
def login():

    global TOKEN
    if TOKEN is not None:
        return TOKEN

    code = get_code()
    url = "https://dev.native.goldau.cn/server/custom/api/customUser/loginWeb"
    body = {
        "appId": 'wx0e296915da6594ae',
        "mobile": mobile,
        "registerChannel": "3",
        "registerSource": "12",
        "smsCode": code
    }
    headers = {
        "Bankcode": "MJT",
        "Branchbankcode": "MJT0001"
    }
    response = requests.post(url, json=body, headers=headers)
    print(f"登录接口返回: {response.json()}")

    assert response.status_code == 200
    json_data = response.json()
    assert 'data' in json_data

    data_value = json_data['data']
    assert 'userTokenInfo' in data_value

    user_token_info = data_value['userTokenInfo']
    assert 'accessToken' in user_token_info

    token = user_token_info['accessToken']
    print(f"完成登录, 获取token: {token}")
    
    set_token(token)
    return token

def post_http(url, body, token):

    headers = {
        "Authorization": f"Bearer {token}",
        "bankCode": "MJT"
    }
    response = requests.post(url, json=body, headers=headers)
    print(f"接口返回: {response.json()}")

    assert response.status_code == 200
    assert 'code' in response.json(), "返回数据不存在code"
    assert response.json()['code']=='0', "获取数据失败"
    assert 'data' in response.json(),"返回数据不存在data"
    return response.json()['data']

@pytest.fixture(scope="session", autouse=True)
def env_setup():
    print("开始测试...")
    yield
    print("测试结束...")

@allure.feature('产品测试模块')
class TestProduct:

    def get_classify_data(self):
        """辅助方法：获取分类数据"""
        token = login()
        url = 'https://mall.test.goldau.cn/server/custom/api/customProduct/commonClassify/queryChoosedParentList'
        data = post_http(url, {}, token)

        assert isinstance(data, list), "返回不是列表"
        return data, token
    
    def get_product_list(self, classify_id, token):
        url = 'https://mall.test.goldau.cn/server/custom/api/customProduct/standardProduct/queryProductListByInvest'
        data = post_http(url, {"classifyId": classify_id}, token)

        assert 'list' in data, "不存在list"
        info_list = data['list']
        assert isinstance(info_list, list), "list不是列表"
        return info_list,token

    @allure.story('产品分类')
    def test_get_classify(self):
        with allure.step('获取分类数据'):
            data, _ = self.get_classify_data()
            # 如果是保存为txt，则使用str(data)
            allure.attach(json.dumps(data, ensure_ascii=False, indent=2), '分类数据', allure.attachment_type.JSON)
       
        assert isinstance(data, list), "返回不是列表"
        assert len(data) > 0, "分类列表为空"

    @allure.story('产品列表')
    def test_get_product_list(self):
        with allure.step('获取分类数据'):
            classify, token = self.get_classify_data()
            
        with allure.step('获取产品列表'):
            url = 'https://mall.test.goldau.cn/server/custom/api/customProduct/standardProduct/queryProductListByInvest'
            report = []
            
            for item in classify:
                with allure.step(f'获取分类 {item["idStr"]} 的产品数据'):
                    data = post_http(url, {"classifyId": item['idStr']}, token)
                    allure.attach(json.dumps(data, ensure_ascii=False, indent=2), '产品数据', allure.attachment_type.JSON)

                    assert 'list' in data, "不存在list"
                    info_list = data['list']
                    assert isinstance(info_list, list), "list不是列表"

                    products = []
                    for info in info_list:
                        products.append({
                            "productId": info['id'],
                            "productName": info['productName']
                        })

                    report.append({
                        "classifyId": item['idStr'],
                        "products": products
                    })
                    
            allure.attach(json.dumps(report, ensure_ascii=False, indent=2), '完整报表数据', allure.attachment_type.JSON)
            assert len(report) > 0, "报表数据为空"

    @allure.story('产品详情模块测试')
    def test_product_info(self):
        with allure.step('首页-获取材质分类'):
            try:
                classifys, token = self.get_classify_data()
            except Exception as e:
                allure.attach(str(e), '获取分类数据失败', allure.attachment_type.TEXT)
                raise 

        for classify in classifys:
            with allure.step(f'分类: {classify["name"]}'):
                # 保存分类详情
                allure.attach(json.dumps(classify, ensure_ascii=False, indent=2), '分类详情', allure.attachment_type.JSON)
            # 如果这个with缩进，则表示这个步骤是分类的步骤，显示上属于分类的下级，与上面分类详情并列，下面代码也有相似地方
            with allure.step('首页-材质分类获取产品列表'): 
                try:
                    # 获取产品列表
                    info_list, token = self.get_product_list(classify['idStr'], token)

                    # 为每个产品创建子步骤
                    for product in info_list:
                        with allure.step(f'产品: {product["productName"]}'):
                            allure.attach(
                                    json.dumps(product, ensure_ascii=False, indent=2),
                                    '产品详情',
                                    allure.attachment_type.JSON
                                )
                        with allure.step('产品购买跳转-产品详情页面'):
                            try:
                                self.get_product_detail(product['id'], token)
                            except Exception as e:
                                allure.attach(str(e), '获取产品详情失败', allure.attachment_type.TEXT)
                except Exception as e:
                    allure.attach(str(e), '获取产品列表失败', allure.attachment_type.TEXT)
                    # 执行下一个分类
                    continue

    # 可以在方法中添加测试报告                
    def get_product_detail(self, product_id, token):

        try:
            detail_url = 'https://mall.test.goldau.cn/server/custom/api/customProduct/detailInfo/detail'
            detail_data = post_http(detail_url, {"productId": product_id}, token)
            allure.attach(json.dumps(detail_data, ensure_ascii=False, indent=2), '产品详情', allure.attachment_type.JSON)
        except Exception as e:  
            allure.attach(str(e), '获取产品详情失败', allure.attachment_type.TEXT)

        try:
            recommend_url = 'https://mall.test.goldau.cn/server/custom/api/customProduct/detailInfo/queryCommentOrRelatedRecommended'
            recommend_data = post_http(recommend_url, {"productId": product_id,"isNeedReturnComment":1}, token)
            allure.attach(json.dumps(recommend_data, ensure_ascii=False, indent=2), '产品推荐', allure.attachment_type.JSON)
        except Exception as e:
            allure.attach(str(e), '获取产品推荐失败', allure.attachment_type.TEXT)

        try:
            direction_url  = 'https://mall.test.goldau.cn/server/custom/api/customUser/systemDirection/selectListByDataCode'
            direction_data = post_http(direction_url, {"dataCodeList":["wechat_share"]}, token)
            allure.attach(json.dumps(direction_data, ensure_ascii=False, indent=2), '获取字典', allure.attachment_type.JSON)
        except Exception as e:
            allure.attach(str(e), '获取字典失败', allure.attachment_type.TEXT)

        try:
            sku_url = f'https://mall.test.goldau.cn/server/custom/api/customProduct/standardProductSpecificationItem/list/{product_id}'
            sku_data = post_http(sku_url, {}, token)
            
            assert isinstance(sku_data, list), "返回不是列表"
            allure.attach(json.dumps(sku_data, ensure_ascii=False, indent=2), 'SKU', allure.attachment_type.JSON)

            all_sku_ids = []
            for item in sku_data:   
                assert 'productSpecificationItemList' in item, "不存在productSpecificationItemList"
                assert isinstance(item['productSpecificationItemList'], list), "productSpecificationItemList不是列表"
                sku_ids = []
                for productSpecificationItem in item['productSpecificationItemList']:
                    sku_ids.append(productSpecificationItem['id'])
                if len(sku_ids) > 0:
                    all_sku_ids.append(sku_ids)
            # 记录收集到的SKU ID
            allure.attach(
                json.dumps(all_sku_ids, ensure_ascii=False, indent=2),
                'SKU ID列表',
                allure.attachment_type.JSON
            )

            if len(all_sku_ids) > 0:
                # 生成笛卡尔积组合
                from itertools import product
                sku_combinations = list(product(*all_sku_ids))

                # 记录笛卡尔积组合
                allure.attach(
                    json.dumps(sku_combinations, ensure_ascii=False, indent=2),
                    '笛卡尔积组合',
                    allure.attachment_type.JSON
                )

            # 由于测试环境存在多sku数据导致笛卡尔积组合数据量过大，暂时不进行测试
            # for sku_combination in sku_combinations:
            #     try:    
            #         combine_url = f'https://mall.test.goldau.cn/server/custom/api/customProduct/specificationCombine/getCombineDetailBySpecificationItemIds/{product_id}/{sku_combination}'
            #         combine_data = post_http(combine_url, {}, token)
            #         allure.attach(json.dumps(combine_data, ensure_ascii=False, indent=2), f'sku组合[{sku_combination}]', allure.attachment_type.JSON)
            #     except Exception as e:
            #         allure.attach(str(e), f'获取sku组合[{sku_combination}]失败', allure.attachment_type.TEXT)

            # 测试第一个sku组合
            if len(sku_combinations) > 0:
                try:    
                    joinStr = ','.join(map(str,sku_combinations[0]))
                    combine_url = f'https://mall.test.goldau.cn/server/custom/api/customProduct/specificationCombine/getCombineDetailBySpecificationItemIds/{product_id}/{joinStr}'
                    combine_data = post_http(combine_url, {}, token)
                    allure.attach(json.dumps(combine_data, ensure_ascii=False, indent=2), f'sku组合[{joinStr}]', allure.attachment_type.JSON)
                except Exception as e:
                    allure.attach(str(e), f'获取sku组合[{joinStr}]失败', allure.attachment_type.TEXT)

        except Exception as e:
            allure.attach(str(e), '获取SKU失败', allure.attachment_type.TEXT)

        if detail_data and detail_data['productBaseInfoResDTO'] and combine_data:
            coupon_body = {"productId":product_id,
                           "categoryId":detail_data['categoryId'],
                           "productName":detail_data['productBaseInfoResDTO']['productName'],
                           "productNumber":detail_data['productBaseInfoResDTO']['productNumber'],
                           "productSkuId":combine_data['id'],
                           "productTypeIds":detail_data['productTypeIds']}

        try:
            coupon_url = 'https://mall.test.goldau.cn/server/custom/api/customCoupon/couponSuitScope/querySuitCoupons'
            coupon_data = post_http(coupon_url, coupon_body, token)
            allure.attach(json.dumps(coupon_data, ensure_ascii=False, indent=2), '优惠券', allure.attachment_type.JSON)
        except Exception as e:
            allure.attach(str(e), '获取优惠券失败', allure.attachment_type.TEXT)

        try:
            suit_scope_url = 'https://mall.test.goldau.cn/server/custom/api/customCoupon/couponReceiveDetail/productSuitScopeQuery'
            suit_scope_data = post_http(suit_scope_url, coupon_body, token)
            allure.attach(json.dumps(suit_scope_data, ensure_ascii=False, indent=2), '适用范围', allure.attachment_type.JSON)
        except Exception as e:
            allure.attach(str(e), '获取适用范围失败', allure.attachment_type.TEXT)

        try:
            gold_url = 'https://mall.test.goldau.cn/server/custom/api/customProduct/goldTexturePriceManage/getAllGoldPrice'
            gold_data = post_http(gold_url, {"goldCode":'AU'}, token)
            allure.attach(json.dumps(gold_data, ensure_ascii=False, indent=2), '金价', allure.attachment_type.JSON)
        except Exception as e:
            allure.attach(str(e), '获取金价失败', allure.attachment_type.TEXT)
    
# 生成报告：allure serve ./allure-results
if __name__ == "__main__":
    pytest.main(['-vs', '--alluredir=./allure-results'])